# -*- coding: utf-8 -*-
#copyright 2009 Kevin Daley
#This file is a part of Cerebra.
#Cerebra is free software: you can redistribute it and/or modify
 #   it under the terms of the GNU  General Public License as published by
  #  the Free Software Foundation, either version 3 of the License, or
   # (at your option) any later version.

   # This program is distributed in the hope that it will be useful,
   # but WITHOUT ANY WARRANTY; without even the implied warranty of
   # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   # GNU  General Public License for more details.

   # You should have received a copy of the GNU  General Public License
   # along with this program.  If not, see <http://www.gnu.org/licenses/>.

#Kevin Daley, Lead Developer.  still.horse@gmail.com.


import numpy, string
import stackless, glob, re, sys, random, numpy, numpy.random, os, pickle, string, urllib
import map2 as map
import socket
from ctypes import *
import struct
from string import *
from math import *
from xml.dom.minidom import parse, parseString
class grammar(map.node, object):
	def __new__(cls, dict=None, *args,**kwds):
		k=object.__new__(cls, " ", *args, **kwds)
		if(dict is None):
			pass
		else:
			c=dict.keys()
			for i in c:
				k.__dict__[i]=dict[i]
		return k
	def __init__(self, *args, **kwds):
		print "passing args to node channel"
		for name in kwds.keys():
			self.__setattr__(name, kwds[name])
	def setup(self):
		norm=1
		if len(self.parents.keys()) !=0:
			self.parent=self.parents[self.parents.keys()[0]] 
			self.neighbors=self.parent.cstrings
		else:
			self.parent=None
			self.neighbors=None
		print "initializing node channel..."
		self.channel = stackless.channel()
		"..creating root node.."
		if not("spectrum" in self.__dict__.keys()):
		  self.spectrum = [i*(numpy.max(data)-numpy.min(data))/64 for i in xrange(64)] if self.parent==None else self.parent.spectrum
		self.input=numpy.fromfile("input.cache")
		map.node.__init__(self, parents={}, children={}, server=self.server, port=self.port, ID=self.ID, offset=[0, 0], cstrings=self.spectrum, estring=string.join((self.spectrum).astype(str).tolist()))
		if(self.__dict__.has_key("tasks")):
			self.tasks=pickle.loads(tasks)
			for i in self.tasks:
				i.insert()
		else:
			self.tasks=[]
			t=stackless.tasklet(self.handle_input)()
			self.tasks.append(t)
			t=stackless.tasklet(self.autobalance)()
			self.tasks.append(t)
			t=stackless.tasklet(self.evolve)()
			self.tasks.append(t) 
			t=stackless.tasklet(self.program)()
			self.tasks.append(t)
			t=stackless.tasklet(self.run)()
			self.tasks.append(t)
		print "..channel initialized"
	def handle_input(self):
		stackless.schedule()
		print "header %i: executing __call__ method"%self.ID
		if(not self.__dict__.has_key("programs")):
			self.programs=[]
		while 1:
			stackless.schedule()			
			k=str(self.channelout.receive())
			print "%s, copy."%(k)
			while(len(self.queue.keys())!=0):
				pass
			
			if "!" in k and k[0]!="!":
				print "do something!"
				if not k in self.programs:
					print k
					self.astring=(";"+k.split("!")[0])
					self.programs.append(k)
				elif not ";" in k:
					self.astring=(k.split("!")[0])
			else:
				raise IOError
			s=self.astring
			self.channelout.send(s)
	def attach_out(channelout):
		self.channelout=channelout
	def __setattr__(self, name, value):
		self.__dict__[name]=value
	def dump(self):
		for i in self.children.keys():
			self.children[i].dump()
		print "preparing node %i for deletion, will dump to stdout"%(self.ID)
		if self.__dict__.has_key("network"):
			return map.node.dump(self)				
					
					
class app:
	def __init__(self,NODE=None, REMOTE=None, Port1=0, Port2=0, GPU=None, Port3=0, stream="", idict=None):
		self.NODE=NODE
		self.REMOTE=REMOTE
		self.PORT1=Port1
		self.PORT2=Port2
		self.GPU=GPU
		self.PORT3=Port3
		self.subnet=1
		self.stream=stream
		self.input=[]
		self.input.append(self.stream)
		self.output=[]
		self.dict=idict
		self.data=None
		self.channel=stackless.channel()
		stackless.tasklet(self.loop)()
		stackless.tasklet(self.balance)()
		stackless.tasklet(self.connection_handler)()
		stackless.tasklet(self.route)()
	def balance(self):
		stackless.schedule()
		while 1:
			stackless.schedule()
			if self.data!=None:
				if self.data.ID!=0:			
					if self.data.parent!=None:
						self.data=self.data.parent
	def loop(self):
			stackless.schedule()
			lp=lambda x,n:1
			n=1
			ch=[]
			while(1):
				stackless.schedule()
				if len(self.input)!=0:
					input=self.input.pop(0)
					if input.split(".").pop()=="xml":
						self.doc=parse(input)
					else:
						self.doc=parseString(input)	
					c=self.doc.getElementsByTagName("command")
					if 1:
						self.data=grammar(ID=int(str(self.NODE)+str(self.PORT1)), children={}, cstrings=[], parents={}, parent=None, estring=str(self.NODE)+str(self.PORT1), server=self.REMOTE, spectrum=numpy.arange(int(str(self.NODE)+str(self.PORT1)),int(str(self.NODE)+str(self.PORT1))+64))
						count=0
						for i in c:
							for counter in xrange(len(i.childNodes)):
								ob0=self.data
								j=i.childNodes[counter]
								n=lp(j,n)
								if j.nodeType!=3 and n:
									inp=j.childNodes[0].nodeValue
									if inp!="....":
										k=j.nodeName
										if k=="desc":
											count=0
											while count<64:
												ch.append(stackless.channel)
												ob=grammar(ID=int(ob0.ID)+64,children={}, parents={}, estring=str(self.NODE)+str(self.PORT1), server=self.GPU, port=self.PORT3, cstrings=[], channelout=ch[count], s=(0,0), unit=float(inp.split(",")[1]), timestep=float(inp.split(",")[2]))
												count+=1
												ob0+=ob
												ob0=ob
												ob.setup()
										elif k=="code":
											exec(inp)
										elif (k=="while"):
											lp=eval(inp)
										elif (k=="remote_data"):
											data.__setattr__(j.getAttrbute('key'),numpy.fromfile(urllib.urlget(inp)))
										elif (k=="val"):
											print "broadcast channel %s"%inp
											ch[inp.split(":")[0]].send(inp.split(":")[1])
											n=ch.receive()
											print "returned %s"%str(n)
											self.output.append((int(n/64),"<val>%i:[%s=%s]!;</val>"%(str(n),inp.split(":")[1],int(n/64))))
									else:	
										self.dict=self.data.dump()
										del self.data
										if j.nodeName=="end":
											sys.exit(0)
	def connection_handler(self):
		stackless.schedule()
		s = socket.socket(socket.AF_TIPC, socket.SOCK_STREAM,0)
		print "client bound to TIPC PORT ", s.getsockname()
		while 1:
			stackless.schedule()
			data = s.recvfrom(65565)[0]
			self.input.append(data)
	def route(self):
		stackless.schedule()
		print 'trying to open the socket'
		s = socket.socket(socket.AF_TIPC, socket.SOCK_STREAM,0)
		while 1:
			stackless.schedule()
			if len(self.output)!=0:
				tmp=self.output.pop()
				tmp2=random.randint(1,100)
				s.sendto(tmp[1],socket.TIPC_ADDR_ID, self.NODE, int(tmp[0])+self.PORT2, 0)

def main():
	print "ON"
	app(int(sys.argv[2]), int(sys.argv[3]), int(sys.argv[4]), int(sys.argv[5]), int(sys.argv[6]), int(sys.argv[7]),sys.argv[1])
	
	t=stackless.run()
	print "OFF"
if __name__=="__main__":
	main()

